#include "KNetScene.h"
#include "KSocket.h"
#include "KSocketAction.h"

#define K_DO_IF(con, todo) do if (con) { (todo); } while (false)

K_ANONYMOUS_NAMESPACE_BEG

struct KContext : KKey {
    explicit KContext(KNetItem *i, KKey *k = NULL) : item(i), key(k) {}
    virtual ~KContext() { delete key; }
    KNetItem *item;
    KKey *key;
};

K_ANONYMOUS_NAMESPACE_END

KNetItem::~KNetItem()
{
}

KSocket *KNetItem::addAcceptor(const KIAddress &addrLocal, KSocketAction *action, int sendBufSize, bool reuseAddrLocal, size_t extra)
{
    assert(m_scene != NULL);
    K_DO_IF(action, action->setItem(this));
    if (KSocket *sock = m_scene->addAcceptor(addrLocal, new KContext(this, action), sendBufSize, reuseAddrLocal, extra)) {
        K_DO_IF(action, action->setSocket(sock));
        return sock;
    }
    return NULL;
}

KSocket *KNetItem::addConnector(const KIAddress &addrLocal, const KIAddress &addrRemote, KSocketAction *action, int sendBufSize, bool reuseAddrLocal)
{
    assert(m_scene != NULL);
    K_DO_IF(action, action->setItem(this));
    if (KSocket *sock = m_scene->addConnector(addrLocal, addrRemote, new KContext(this, action), sendBufSize, reuseAddrLocal)) {
        K_DO_IF(action, action->setSocket(sock));
        return sock;
    }
    return NULL;
}

KSocket *KNetItem::addMessenger(const KIAddress &addrLocal, KSocketAction *action, int sendBufSize, bool reuseAddrLocal)
{
    assert(m_scene != NULL);
    K_DO_IF(action, action->setItem(this));
    if (KSocket *sock = m_scene->addMessenger(addrLocal, new KContext(this, action), sendBufSize, reuseAddrLocal)) {
        K_DO_IF(action, action->setSocket(sock));
        return sock;
    }
    return NULL;
}

KSocketAction *KNetItem::getAction(KSocket *sock)
{
    if (sock) {
        if (KContext *context = static_cast<KContext *>(sock->key())) {
            return static_cast<KSocketAction *>(context->key);
        }
    }
    return NULL;
}

bool KNetItem::setAction(KSocket *sock, KSocketAction *action, bool take)
{
    if (sock) {
        if (KContext *context = static_cast<KContext *>(sock->key())) {
            assert(context->item == this);
            if (action) {
                action->setItem(this);
                action->setSocket(sock);
            }
            context->key = action;
            return true;
        }
    }
    if (take) {
        delete action;
    }
    return false;
}

bool KNetItem::postMessage(KSocket *sock, KKey *key)
{
    assert(m_scene != NULL);
    return m_scene->postMessage(sock, key);
}

bool KNetItem::receive(KSocket *sock, size_t length, KKey *key)
{
    assert(m_scene != NULL);
    return m_scene->receive(sock, length, key);
}

bool KNetItem::send(KSocket *sock, KStorage *storage, size_t length)
{
    assert(m_scene != NULL);
    return m_scene->send(sock, storage, length);
}

bool KNetItem::send(KSocket *sock, const void *data, size_t length, KKey *key)
{
    assert(m_scene != NULL);
    return m_scene->send(sock, data, length, key);
}

bool KNetItem::transmit(KSocket *sock, HANDLE hFile, size_t length, KKey *key, size_t blockLen, KPackage *head, KPackage *tail)
{
    assert(m_scene != NULL);
    return m_scene->transmit(sock, hFile, length, key, blockLen, head, tail);
}

bool KNetItem::sendTo(KSocket *sock, const KIAddress &addrRemote, const void *data, size_t length, KKey *key)
{
    assert(m_scene != NULL);
    return m_scene->sendTo(sock, addrRemote, data, length, key);
}

void KNetItem::ensureAlive(KSocket *sock, bool always)
{
    assert(m_scene != NULL);
    m_scene->ensureAlive(sock, always);
}

KDef::Life KNetItem::lifeBegin(KSocket *sock)
{
    assert(m_scene != NULL);
    return m_scene->lifeBegin(sock);
}

void KNetItem::lifeEnd(KSocket *sock, KDef::Life life)
{
    assert(m_scene != NULL);
    m_scene->lifeEnd(sock, life);
}

void KNetItem::onAccepted(KSocket *sock, KKey *key)
{
    if (KSocketAction *action = static_cast<KSocketAction *>(key)) {
        action->onAccepted(sock);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onAccepted()");
    }
}

void KNetItem::onFatalError(KSocket *sock, KDef::SockError type, DWORD error)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onFatalError(type, error);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onFatalError()");
    }
}

void KNetItem::onConnected(KSocket *sock)
{
    if (KSocketAction *action = getAction(sock)) {
        action->setSocket(sock);
        action->onConnected();
    } else {
        KDebugMsg("Warning: ignore KNetItem::onConnected()");
    }
}

void KNetItem::onTransmitted(KSocket *sock, KKey *&key, HANDLE file, size_t length)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onTransmitted(key, file, length);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onTransmitted()");
    }
}

void KNetItem::onCreated(KSocket *sock)
{
    if (KSocketAction *action = getAction(sock)) {
        action->setSocket(sock);
        action->onCreated();
    } else {
        KDebugMsg("Warning: ignore KNetItem::onCreated()");
    }
}

void KNetItem::onClosing(KSocket *sock, bool stopped)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onClosing(stopped);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onClosing()");
    }
}

void KNetItem::onError(KSocket *sock, KDef::SockError type, DWORD error)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onError(type, error);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onError()");
    }
}

void KNetItem::onMessage(KSocket *sock, KKey *&key)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onMessage(key);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onMessage()");
    }
}

void KNetItem::onReceived(KSocket *sock, KKey *&key, void *data, size_t length, bool more)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onReceived(key, data, length, more);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onReceived()");
    }
}

void KNetItem::onSent(KSocket *sock, KKey *&key, void *data, size_t length)
{
    if (KSocketAction *action = getAction(sock)) {
        action->onSent(key, data, length);
    } else {
        KDebugMsg("Warning: ignore KNetItem::onSent()");
    }
}

KNetScene::KNetScene(size_t numOfWorkers, size_t maxPoolSize, size_t chunkSize) : KMultiplexor(numOfWorkers)
{
    setChunkSize(chunkSize);
    setMaxPoolSize(maxPoolSize);
}

KNetScene::~KNetScene()
{
    stopAll();
    for (auto item = m_items.cbegin(); item != m_items.cend(); ++item) {
        (*item)->m_scene = NULL;
    }
}

void KNetScene::install(KNetItem *item)
{
    if (item && !item->m_scene) {
        item->m_scene = this;
        {
            KLocker lock(*this);
            m_items.push_back(item);
        }
        if (isRunning()) {
            item->onStarted();
        }
    }
}

bool KNetScene::stopAll()
{
    return stop(INFINITE);
}

void KNetScene::onAccepted(KSocket *sock, KKey *key)
{
    if (KContext *context = static_cast<KContext *>(key)) {
        if (context->item->filter() & KNetItem::FilterAccepted) {
            sock->setKey(new KContext(context->item));
            auto life = lifeBegin(sock);
            context->item->onAccepted(sock, context->key);
            lifeEnd(sock, life);
        } else {
            sock->shutdown();
            sock->close();
        }
    }
}

void KNetScene::onClosing(KSocket *sock, bool stopped)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterClosing) {
            context->item->onClosing(sock, stopped);
        }
    }
}

void KNetScene::onConnected(KSocket *sock)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterConnected) {
            context->item->onConnected(sock);
        } else {
            sock->shutdown();
            sock->close();
        }
    }
}

void KNetScene::onCreated(KSocket *sock)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterCreated) {
            auto life = lifeBegin(sock);
            context->item->onCreated(sock);
            lifeEnd(sock, life);
        }
    }
}

void KNetScene::onError(KSocket *sock, KDef::SockError type, DWORD error)
{
    if (sock) {
        if (type == KDef::ErrorUpdateContext) {
            assert(false);
        } else if (KContext *context = static_cast<KContext *>(sock->key())) {
            if (context->item->filter() & KNetItem::FilterError) {
                switch (type) {
                case KDef::ErrorCallAccept:
                case KDef::ErrorClientInit:
                case KDef::ErrorFailedAccept:
                    context->item->onFatalError(sock, type, error);
                    break;
                default:
                    context->item->onError(sock, type, error);
                    break;
                }
            }
        }
    }
}

void KNetScene::onMessage(KSocket *sock, KKey *&key)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterMessage) {
            context->item->onMessage(sock, key);
        }
    }
}

void KNetScene::onReceived(KSocket *sock, KKey *&key, void *&data, size_t length, bool more)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterReceived) {
            context->item->onReceived(sock, key, data, length, more);
        }
    }
}

void KNetScene::onSent(KSocket *sock, KKey *&key, void *&data, size_t length)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterSent) {
            context->item->onSent(sock, key, data, length);
        }
    }
}

void KNetScene::onStopping()
{
    std::vector<KNetItem *> items;
    {
        KLocker lock(*this);
        items = m_items;
    }
    for (auto item = items.cbegin(); item != items.cend(); ++item) {
        (*item)->onStopping();
    }
}

void KNetScene::onTransmitted(KSocket *sock, KKey *&key, HANDLE file, size_t length)
{
    if (KContext *context = static_cast<KContext *>(sock->key())) {
        if (context->item->filter() & KNetItem::FilterTransmitted) {
            context->item->onTransmitted(sock, key, file, length);
        }
    }
}

bool KNetScene::startImp()
{
    bool ok = KMultiplexor::startImp();
    if (ok) {
        std::vector<KNetItem *> items = m_items;
        for (auto item = items.cbegin(); item != items.cend(); ++item) {
            assert((*item)->m_scene == this);
            (*item)->onStarted();
        }
    }
    return ok;
}

bool KNetScene::stopImp(DWORD ms)
{
    bool ok = KMultiplexor::stopImp(ms);
    if (ok) {
        for (auto item = m_items.crbegin(); item != m_items.crend(); ++item) {
            (*item)->onStopped();
        }
    }
    return ok;
}